package tech.wetech.admin3.sys.service.impl;

import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tech.wetech.admin3.config.WxV3PayConfig;
import tech.wetech.admin3.dtos.NativePayParamsDto;
import tech.wetech.admin3.dtos.NotifyDto;
import tech.wetech.admin3.sys.service.AooCountService;
import tech.wetech.admin3.sys.service.NativePayService;
import tech.wetech.admin3.util.WxPayHttpClientBuilder;
import com.fasterxml.jackson.core.type.TypeReference;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class NativePayServiceimpl implements NativePayService {
  private CloseableHttpClient httpClient;
  @Autowired
  private AooCountService countService;

  // 支付成功回调通知
  @Override
  public Map<String, String> payNotify(NotifyDto dto) {
    // 验签
    // 解密
    // 业务处理
    // 返回结果
    Map<String, String> res = null;
    // 解密微信传递过来的数据
    try {
      String json = new AesUtil(WxV3PayConfig.apiV3Key.getBytes()).decryptToString(
        dto.getResource().getAssociated_data().getBytes(),
        dto.getResource().getNonce().getBytes(),
        dto.getResource().getCiphertext());
      Map<String, Object> data = JSON.parseObject(json, Map.class);
      System.out.println("data---\n" + data);
      String tradeState = data.get("trade_state").toString();
      if ("SUCCESS".equals(tradeState)) {
        // 业务处理
        // 1. 更新订单状态
        // 2. 发货
        // 3. ....
        String out_trade_no = data.get("out_trade_no").toString();

        countService.updateOrder(out_trade_no);
        System.out.println("(微信)支付成功通知..." + out_trade_no);

      }
    } catch (Exception e) {
      e.printStackTrace();
      res.put("code", "FAIL");
      res.put("message", "微信支付通知失败");
    }
    return res;
  }


  @Value("${wxpay.notify_url}")
  private String notify_url;

  @Value("${order.description}")
  private String description;

  @Value("${order.orderAmountWx}")
  private String orderAmountWx;

  // 创建订单
  @Override
  public Map<String, String> createOrder(String out_trade_no) throws IOException {
    Map<String, String> res = new HashMap<>();

    System.out.println("微信notify_url---" + notify_url);

    NativePayParamsDto dto = new NativePayParamsDto(out_trade_no, Integer.parseInt(orderAmountWx) , description, notify_url);
    HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(dto);

    StringEntity entity = new StringEntity(json, "utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");

    //完成签名并执行请求
    httpClient = new WxPayHttpClientBuilder().buildClient();
    CloseableHttpResponse response = httpClient.execute(httpPost);

    try {
      int statusCode = response.getStatusLine().getStatusCode();
      String responseBody = EntityUtils.toString(response.getEntity());
//      System.out.println("responseBody---\n" + responseBody);

      if (statusCode == 200) { //处理成功
        Map<String, Object> responseMap = objectMapper.readValue(responseBody, new TypeReference<Map<String, Object>>() {
        });
        String qrCodeUrl = (String) responseMap.get("code_url");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        QrCodeUtil.generate(qrCodeUrl, 300, 300, "png", outputStream);
        String qrCodeBase64 = Base64.getEncoder().encodeToString(outputStream.toByteArray());

        res.put("code", "success");
        res.put("out_trade_no", out_trade_no);
        res.put("qr_code", qrCodeBase64);
        return res;
      } else if (statusCode == 204) { //处理成功，无返回Body
        return res;
      } else {
        res = JSON.parseObject(responseBody, Map.class);
        return res;
      }
    } finally {
      response.close();
    }

  }

  // 查询支付结果
  @Override
  public Map<String, String> queryOrder(String out_trade_no) throws IOException {
    Map<String, String> res = new HashMap<>();

    HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + out_trade_no + "?mchid=" + WxV3PayConfig.mchId);
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    httpClient = new WxPayHttpClientBuilder().buildClient();
    CloseableHttpResponse response = httpClient.execute(httpGet);

    System.out.println("微信订单查询接口响应：" + response);

    try {
      int statusCode = response.getStatusLine().getStatusCode();
      String responseBody = EntityUtils.toString(response.getEntity());
      if (statusCode == 200) { //处理成功
        System.out.println("success,return body = " + responseBody);
        Map<String, Object> responseMap = new ObjectMapper().readValue(responseBody, new TypeReference<Map<String, Object>>() {
        });
        String outTradeNo = (String) responseMap.get("out_trade_no");
        String tradeState = (String) responseMap.get("trade_state");
        String tradeStateDesc = (String) responseMap.get("trade_state_desc");

        res.put("outTradeNo", outTradeNo);
        res.put("tradeState", tradeState);
        res.put("tradeStateDesc", tradeStateDesc);
      } else if (statusCode == 204) { //处理成功，无返回Body
        System.out.println("success");
      } else {
        System.out.println("failed,resp code = " + statusCode + ",\nreturn body = " + responseBody);
        Map<String, Object> responseMap = new ObjectMapper().readValue(responseBody, new TypeReference<Map<String, Object>>() {
        });
        String code = (String) responseMap.get("code");
        String message = (String) responseMap.get("message");

        res.put("code", code);
        res.put("message", message);
        return res;
//        throw new IOException("request failed");
      }
    } finally {
      response.close();
    }

    return res;
  }


}
